//
// System.Drawing.Pen unit tests
//
// Authors:
//	Sebastien Pouliot  <sebastien@ximian.com>
//
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using SC = System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Security.Permissions;
using NUnit.Framework;

namespace MonoTests.System.Drawing {

	[TestFixture]
	public class PenTest {

		private Pen default_pen;
		private CustomLineCap custom_line_cap;

		[TestFixtureSetUp]
		public void FixtureSetUp ()
		{
			default_pen = new Pen (Color.Empty);
			custom_line_cap = new CustomLineCap (new GraphicsPath (), new GraphicsPath ());
		}

		private void Check (Pen p)
		{
			Assert.AreEqual (PenAlignment.Center, p.Alignment, "MiterLimit");
			Assert.AreEqual (typeof (SolidBrush), p.Brush.GetType (), "Brush.Type");
			Assert.AreEqual (Color.Red.ToArgb (), (p.Brush as SolidBrush).Color.ToArgb (), "Brush.Color");
			Assert.AreEqual (Color.Red.ToArgb (), p.Color.ToArgb (), "Color");
			Assert.AreEqual (0, p.CompoundArray.Length, "CompoundArray");
			Assert.AreEqual (DashCap.Flat, p.DashCap, "DashCap");
			Assert.AreEqual (0, p.DashOffset, "DashOffset");
			Assert.AreEqual (DashStyle.Solid, p.DashStyle, "DashStyle");
			Assert.AreEqual (LineCap.Flat, p.EndCap, "EndCap");
			Assert.AreEqual (LineJoin.Miter, p.LineJoin, "LineJoin");
			Assert.AreEqual (10, p.MiterLimit, "MiterLimit");
			Assert.AreEqual (PenType.SolidColor, p.PenType, "PenType");
			Assert.AreEqual (LineCap.Flat, p.StartCap, "StartCap");
			Assert.IsTrue (p.Transform.IsIdentity, "Transform");
		}

		[Test]
		public void Constructor_Color ()
		{
			using (Pen p = new Pen (Color.Red)) {
				Assert.AreEqual (1, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Color_Float ()
		{
			using (Pen p = new Pen (Color.Red, 2.5f)) {
				Assert.AreEqual (2.5f, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Color_Float_Zero ()
		{
			using (Pen p = new Pen (Color.Red, 0.0f)) {
				Assert.AreEqual (0.0f, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Color_Float_Negative ()
		{
			using (Pen p = new Pen (Color.Red, -2)) {
				Assert.AreEqual (-2, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Color_Float_MaxValue ()
		{
			using (Pen p = new Pen (Color.Red, Single.MaxValue)) {
				Assert.AreEqual (Single.MaxValue, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Brush ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				Assert.AreEqual (1, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Brush_Null ()
		{
			Assert.Throws<ArgumentNullException> (() => new Pen ((Brush) null));
		}

		[Test]
		public void Constructor_Brush_Float ()
		{
			using (Pen p = new Pen (Brushes.Red, 2.5f)) {
				Assert.AreEqual (2.5f, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Brush_Float_Null ()
		{
			Assert.Throws<ArgumentNullException> (() => new Pen ((Brush) null, Single.MaxValue));
		}

		[Test]
		public void Constructor_Brush_Float_Zero ()
		{
			using (Pen p = new Pen (Brushes.Red, 0.0f)) {
				Assert.AreEqual (0.0f, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Brush_Float_Negative ()
		{
			using (Pen p = new Pen (Brushes.Red, -2)) {
				Assert.AreEqual (-2, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Brush_Float_MaxValue ()
		{
			using (Pen p = new Pen (Brushes.Red, Single.MaxValue)) {
				Assert.AreEqual (Single.MaxValue, p.Width, "Width");
				Check (p);
			}
		}

		[Test]
		public void Constructor_Brush_DisposeBeforeUse ()
		{
			using (SolidBrush b = new SolidBrush (Color.Red)) {
				using (Pen p = new Pen (b, 1)) {
					b.Dispose ();
					Check (p);
					using (Bitmap bmp = new Bitmap (12, 12)) {
						using (Graphics g = Graphics.FromImage (bmp)) {
							g.DrawLine (p, 1, 1, 10, 10);
						}
					}
				}
			}
		}

		private void Check2 (Pen p)
		{
			Assert.AreEqual (typeof (SolidBrush), p.Brush.GetType (), "Brush.Type");
			Assert.AreEqual (Color.Red.ToArgb (), (p.Brush as SolidBrush).Color.ToArgb (), "Brush.Color");
			Assert.AreEqual (Color.Red.ToArgb (), p.Color.ToArgb (), "Color");
			Assert.AreEqual (0, p.CompoundArray.Length, "CompoundArray");
			//			Assert.AreEqual (DashCap.Flat, p.DashCap, "DashCap");
			Assert.AreEqual (0, p.DashOffset, "DashOffset");
			Assert.AreEqual (10, p.MiterLimit, "MiterLimit");
			Assert.AreEqual (PenType.SolidColor, p.PenType, "PenType");
			Assert.IsTrue (p.Transform.IsIdentity, "Transform");
		}

		[Test]
		public void Alignment ()
		{
			using (Pen p = new Pen (Brushes.Gold, Single.NegativeInfinity)) {
				foreach (PenAlignment pa in Enum.GetValues (typeof (PenAlignment))) {
					p.Alignment = pa;
					Assert.AreEqual (pa, p.Alignment, pa.ToString ());
				}
			}
		}

		[Test]
		public void Alignment_Invalid ()
		{
			Assert.Throws<SC.InvalidEnumArgumentException> (() => default_pen.Alignment = (PenAlignment) Int32.MinValue);
		}

		[Test]
		public void Brush_Dispose ()
		{
			using (Pen p = new Pen (Brushes.Red, 2.5f)) {
				// are we getting the original brush ?
				Brush b1 = p.Brush;
				b1.Dispose ();
				Check (p);
				using (Pen clone = (Pen) p.Clone ()) {
					Check (clone);
				}
				Assert.IsFalse (Object.ReferenceEquals (b1, p.Brush), "Brush");
				// nope :)
			}
		}

		[Test]
		public void Brush_Null ()
		{
			Assert.Throws<ArgumentNullException> (() => default_pen.Brush = null);
		}

		[Test]
		[Category ("NotWorking")] // not supported by libgdiplus
		public void CustomEndCap_Set ()
		{
			using (Pen p = new Pen (Brushes.DeepSkyBlue, -1)) {
				p.CustomEndCap = custom_line_cap;
				Assert.IsNotNull (p.CustomEndCap, "CustomEndCap");
				Assert.IsFalse (Object.ReferenceEquals (custom_line_cap, p.CustomEndCap), "!same");
			}
		}

		[Test]
		[Category ("NotWorking")] // not supported by libgdiplus
		public void CustomEndCap_Default ()
		{
			Assert.Throws<ArgumentException> (() => { var x = default_pen.CustomEndCap; });
		}

		[Test]
		[Category ("NotWorking")] // not supported by libgdiplus
		public void CustomStartCap_Set ()
		{
			using (Pen p = new Pen (Brushes.Ivory, 5)) {
				p.CustomStartCap = custom_line_cap;
				Assert.IsNotNull (p.CustomStartCap, "CustomStartCap");
				Assert.IsFalse (Object.ReferenceEquals (custom_line_cap, p.CustomStartCap), "!same");
			}
		}

		[Test]
		[Category ("NotWorking")] // not supported by libgdiplus
		public void CustomStartCap_Default ()
		{
			Assert.Throws<ArgumentException> (() => { var x = default_pen.CustomStartCap; });
		}

		[Test]
		public void DashCap_Valid ()
		{
			// note: YellowGreen is broken by a destructive test so we can't use it afterward
			// note: this worked with nunit 2.2 because this test was executed before the destructive one
			using (Pen p = new Pen (Brushes.Yellow, 0)) {
				foreach (DashCap dc in Enum.GetValues (typeof (DashCap))) {
					p.DashCap = dc;
					Assert.AreEqual (dc, p.DashCap, dc.ToString ());
				}
			}
		}

		[Test]
		public void DashCap_Invalid ()
		{
			Assert.Throws<SC.InvalidEnumArgumentException> (() => default_pen.DashCap = (DashCap) Int32.MinValue);
		}

		[Test]
		public void DashOffset ()
		{
			using (Pen p = new Pen (Brushes.Transparent, 32)) {
				p.DashOffset = 0;
				Assert.AreEqual (0, p.DashOffset, "0");
				p.DashOffset = Single.MaxValue;
				Assert.AreEqual (Single.MaxValue, p.DashOffset, "MaxValue");
				p.DashOffset = Single.MinValue;
				Assert.AreEqual (Single.MinValue, p.DashOffset, "MinValue");
			}
		}

		[Test]
		public void DashPattern ()
		{
			using (Pen p = new Pen (Brushes.Tomato, 1.1f)) {
				Assert.AreEqual (DashStyle.Solid, p.DashStyle, "Solid");
				p.DashPattern = new float[1] { 1 };
				Assert.AreEqual (DashStyle.Custom, p.DashStyle, "Custom");
				Assert.AreEqual (1, p.DashPattern.Length, "DashPattern");
			}
		}

		[Test]
		public void DashPattern_Empty ()
		{
			Assert.Throws<ArgumentException> (() => default_pen.DashPattern = new float[0]);
		}

		[Test]
		public void DashStyle_Valid ()
		{
			using (Pen p = new Pen (Brushes.Silver, Single.PositiveInfinity)) {
				foreach (DashStyle ds in Enum.GetValues (typeof (DashStyle))) {
					p.DashStyle = ds;
					Assert.AreEqual (ds, p.DashStyle, ds.ToString ());
				}
			}
		}

		[Test]
		public void DashStyle_Invalid ()
		{
			Assert.Throws<SC.InvalidEnumArgumentException> (() => default_pen.DashStyle = (DashStyle) Int32.MinValue);
		}

		[Test]
		public void DashStyle_Custom ()
		{
			using (Pen p = new Pen (Brushes.Silver, Single.PositiveInfinity)) {
				Assert.AreEqual (DashStyle.Solid, p.DashStyle, "Solid");
				// can't ask for Solid (default) -> OutOfMemoryException
				p.DashStyle = DashStyle.Custom;
				Assert.AreEqual (DashStyle.Custom, p.DashStyle, "Solid->Custom");
				Assert.AreEqual (1, p.DashPattern.Length, "Solid->Custom.Length");
				Assert.AreEqual (1, p.DashPattern[0], "Solid->Custom[0]");

				p.DashStyle = DashStyle.Dot;
				Assert.AreEqual (DashStyle.Dot, p.DashStyle, "Dot");
				Assert.AreEqual (2, p.DashPattern.Length, "Dot.Length");
				Assert.AreEqual (1, p.DashPattern[0], "Dot[0]");
				Assert.AreEqual (1, p.DashPattern[1], "Dot[1]");
				p.DashStyle = DashStyle.Custom;
				Assert.AreEqual (DashStyle.Custom, p.DashStyle, "Dot->Custom");
				Assert.AreEqual (2, p.DashPattern.Length, "Dot->Custom.Length");
				Assert.AreEqual (1, p.DashPattern[0], "Dot->Custom[0]");
				Assert.AreEqual (1, p.DashPattern[1], "Dot->Custom[1]");

				p.DashStyle = DashStyle.Dash;
				Assert.AreEqual (DashStyle.Dash, p.DashStyle, "Dash");
				Assert.AreEqual (2, p.DashPattern.Length, "Dash.Length");
				Assert.AreEqual (3, p.DashPattern[0], "Dash[0]");
				Assert.AreEqual (1, p.DashPattern[1], "Dash[1]");
				p.DashStyle = DashStyle.Custom;
				Assert.AreEqual (DashStyle.Custom, p.DashStyle, "Dash->Custom");
				Assert.AreEqual (2, p.DashPattern.Length, "Dash->Custom.Length");
				Assert.AreEqual (3, p.DashPattern[0], "Dash->Custom[0]");
				Assert.AreEqual (1, p.DashPattern[1], "Dash->Custom[1]");

				p.DashStyle = DashStyle.DashDot;
				Assert.AreEqual (DashStyle.DashDot, p.DashStyle, "DashDot");
				Assert.AreEqual (4, p.DashPattern.Length, "DashDot.Length");
				Assert.AreEqual (3, p.DashPattern[0], "DashDot[0]");
				Assert.AreEqual (1, p.DashPattern[1], "DashDot[1]");
				Assert.AreEqual (1, p.DashPattern[2], "DashDot[2]");
				Assert.AreEqual (1, p.DashPattern[3], "DashDot[3]");
				p.DashStyle = DashStyle.Custom;
				Assert.AreEqual (DashStyle.Custom, p.DashStyle, "DashDot->Custom");
				Assert.AreEqual (4, p.DashPattern.Length, "DashDot->Custom.Length");
				Assert.AreEqual (3, p.DashPattern[0], "DashDot->Custom[0]");
				Assert.AreEqual (1, p.DashPattern[1], "DashDot->Custom[1]");
				Assert.AreEqual (1, p.DashPattern[2], "DashDot->Custom[2]");
				Assert.AreEqual (1, p.DashPattern[3], "DashDot->Custom[3]");

				p.DashStyle = DashStyle.DashDotDot;
				Assert.AreEqual (DashStyle.DashDotDot, p.DashStyle, "DashDotDot");
				Assert.AreEqual (6, p.DashPattern.Length, "DashDotDot.Length");
				Assert.AreEqual (3, p.DashPattern[0], "DashDotDot[0]");
				Assert.AreEqual (1, p.DashPattern[1], "DashDotDot[1]");
				Assert.AreEqual (1, p.DashPattern[2], "DashDotDot[2]");
				Assert.AreEqual (1, p.DashPattern[3], "DashDotDot[3]");
				Assert.AreEqual (1, p.DashPattern[2], "DashDotDot[2]");
				Assert.AreEqual (1, p.DashPattern[3], "DashDotDot[3]");
				p.DashStyle = DashStyle.Custom;
				Assert.AreEqual (DashStyle.Custom, p.DashStyle, "DashDotDot->Custom");
				Assert.AreEqual (6, p.DashPattern.Length, "DashDotDot->Custom.Length");
				Assert.AreEqual (3, p.DashPattern[0], "DashDotDot->Custom[0]");
				Assert.AreEqual (1, p.DashPattern[1], "DashDotDot->Custom[1]");
				Assert.AreEqual (1, p.DashPattern[2], "DashDotDot->Custom[2]");
				Assert.AreEqual (1, p.DashPattern[3], "DashDotDot->Custom[3]");
				Assert.AreEqual (1, p.DashPattern[2], "DashDotDot->Custom[2]");
				Assert.AreEqual (1, p.DashPattern[3], "DashDotDot->Custom[3]");

				// resetting to DashStyle.Solid doesn't throw the OutOfMemoryException
				// on MS runtime
				p.DashStyle = DashStyle.Solid;
				Assert.AreEqual (DashStyle.Solid, p.DashStyle, "Solid-2");
				Assert.AreEqual (0, p.DashPattern.Length, "Solid2.Length");
				p.DashStyle = DashStyle.Custom;
				Assert.AreEqual (DashStyle.Custom, p.DashStyle, "Solid2->Custom");
				Assert.AreEqual (1, p.DashPattern.Length, "Solid2->Custom.Length");
				Assert.AreEqual (1, p.DashPattern[0], "Solid2->Custom[0]");
			}
		}

		[Test]
		[Category ("NotWorking")] // MS bug reported as FDBK50053
		public void DashPattern_Default ()
		{
			Assert.Throws<OutOfMemoryException> (() => { var x = default_pen.DashPattern; });
		}

		[Test]
		public void EndCap_Valid ()
		{
			using (Pen p = new Pen (Brushes.Silver, Single.PositiveInfinity)) {
				foreach (LineCap lc in Enum.GetValues (typeof (LineCap))) {
					p.EndCap = lc;
					Assert.AreEqual (lc, p.EndCap, lc.ToString ());
				}
			}
		}

		[Test]
		public void EndCap_Invalid ()
		{
			Assert.Throws<SC.InvalidEnumArgumentException> (() => default_pen.EndCap = (LineCap) Int32.MinValue);
		}

		[Test]
		public void LineJoin_Valid ()
		{
			using (Pen p = new Pen (Brushes.Chocolate, Single.NaN)) {
				foreach (LineJoin lj in Enum.GetValues (typeof (LineJoin))) {
					p.LineJoin = lj;
					Assert.AreEqual (lj, p.LineJoin, lj.ToString ());
				}
			}
		}

		[Test]
		public void LineJoin_Invalid ()
		{
			Assert.Throws<SC.InvalidEnumArgumentException> (() => default_pen.LineJoin = (LineJoin) Int32.MinValue);
		}

		[Test]
		public void MiterLimit ()
		{
			using (Pen p = new Pen (Brushes.Tan, 1)) {
				p.MiterLimit = Single.MinValue;
				Assert.AreEqual (1, p.MiterLimit, "MinValue/1");
				p.MiterLimit = 0;
				Assert.AreEqual (1, p.MiterLimit, "0/1");
				p.MiterLimit = Single.MaxValue;
				Assert.AreEqual (Single.MaxValue, p.MiterLimit, "MaxValue");
			}
		}

		[Test]
		public void StartCap_Valid ()
		{
			using (Pen p = new Pen (Brushes.Silver, Single.PositiveInfinity)) {
				foreach (LineCap lc in Enum.GetValues (typeof (LineCap))) {
					p.StartCap = lc;
					Assert.AreEqual (lc, p.StartCap, lc.ToString ());
				}
			}
		}

		[Test]
		public void StartCap_Invalid ()
		{
			Assert.Throws<SC.InvalidEnumArgumentException> (() => default_pen.StartCap = (LineCap) Int32.MinValue);
		}

		[Test]
		public void Transform_Null ()
		{
			Assert.Throws<ArgumentNullException> (() => default_pen.Transform = null);
		}

		[Test]
		public void Transform_NonInvertible ()
		{
			using (Pen p = new Pen (Brushes.Snow, Single.MaxValue)) {
				Assert.Throws<ArgumentException> (() => p.Transform = new Matrix (123, 24, 82, 16, 47, 30));
			}
		}

		[Test]
		public void Width ()
		{
			using (Pen p = new Pen (Brushes.Tan, Single.MinValue)) {
				Assert.AreEqual (Single.MinValue, p.Width, "MinValue");
				p.Width = 0;
				Assert.AreEqual (0, p.Width, "0");
				p.Width = Single.MaxValue;
				Assert.AreEqual (Single.MaxValue, p.Width, "MaxValue");
			}
		}

		[Test]
		public void Clone ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				using (Pen clone = (Pen) p.Clone ()) {
					Check (clone);
				}
			}
		}

		[Test]
		public void Dispose ()
		{
			Pen p = new Pen (Brushes.Red);
			p.Dispose ();
			Assert.Throws<ArgumentException> (() => p.Alignment = PenAlignment.Center);
			// exception but not an ObjectDisposedException
		}

		[Test]
		public void SetLineCap ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				foreach (LineCap sc in Enum.GetValues (typeof (LineCap))) {
					foreach (LineCap ec in Enum.GetValues (typeof (LineCap))) {
						foreach (DashCap dc in Enum.GetValues (typeof (DashCap))) {
							string s = String.Format ("{0}-{1}-{2}", sc, ec, dc);
							p.SetLineCap (sc, ec, dc);
							Assert.AreEqual (sc, p.StartCap, s + ".StartCap");
							Assert.AreEqual (ec, p.EndCap, s + ".EndCap");
							Assert.AreEqual (dc, p.DashCap, s + ".DashCap");
						}
					}
				}
			}
		}

		[Test]
		public void SetLineCap_InvalidStartCap ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				p.SetLineCap ((LineCap)Int32.MinValue, LineCap.Flat, DashCap.Flat);
				// no exception :( (reported as FDBK50057)
				Assert.AreEqual (Int32.MinValue, (int) p.StartCap, "StartCap");
				Assert.AreEqual (LineCap.Flat, p.EndCap, "EndCap");
				Assert.AreEqual (DashCap.Flat, p.DashCap, "DashCap");
			}
		}

		[Test]
		public void SetLineCap_InvalidEndCap ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				p.SetLineCap (LineCap.Flat, (LineCap)Int32.MinValue, DashCap.Flat);
				// no exception :( (reported as FDBK50057)
				Assert.AreEqual (LineCap.Flat, p.StartCap, "StartCap");
				Assert.AreEqual (Int32.MinValue, (int)p.EndCap, "EndCap");
				Assert.AreEqual (DashCap.Flat, p.DashCap, "DashCap");
			}
		}

		[Test]
		public void SetLineCap_InvalidDashCap ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				p.SetLineCap (LineCap.Flat, LineCap.Flat, (DashCap)Int32.MinValue);
				Assert.AreEqual (LineCap.Flat, p.StartCap, "StartCap");
				Assert.AreEqual (LineCap.Flat, p.EndCap, "EndCap");
				// invalid value was reseted to Flat (reported as FDBK50057)
				Assert.AreEqual (DashCap.Flat, p.DashCap, "DashCap");
			}
		}

		[Test]
		//[ExpectedException (typeof (ArgumentNullException))] // reported as FDBK50058
		public void MultiplyTransform1_Null ()
		{
			Assert.Throws<NullReferenceException> (() => default_pen.MultiplyTransform (null));
		}

		[Test]
		//[ExpectedException (typeof (ArgumentNullException))] // reported as FDBK50058
		public void MultiplyTransform2_Null ()
		{
			Assert.Throws<NullReferenceException> (() => default_pen.MultiplyTransform (null, MatrixOrder.Append));
		}

		[Test]
		public void MultiplyTransform2_InvalidMatrixOrder ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				Matrix m1 = new Matrix (2, 0.5f, 0.5f, 4, 10, 20);
				Matrix m2 = new Matrix (1, 0, 0, 1, -50, -30);

				p.Transform = m2;
				p.MultiplyTransform (m1, (MatrixOrder) Int32.MinValue);
				// no exception, but which order is it ?
				Matrix invalid = p.Transform;

				p.Transform = m2;
				p.MultiplyTransform (m1, MatrixOrder.Append);
				Assert.IsTrue (invalid.Equals (p.Transform), "Append");

				p.Transform = m2;
				p.MultiplyTransform (m1, MatrixOrder.Prepend);
				Assert.IsFalse (invalid.Equals (p.Transform), "Prepend");
			}
		}

		[Test]
		public void MultiplyTransform_NonInvertible ()
		{
			using (Matrix noninvertible = new Matrix (123, 24, 82, 16, 47, 30)) {
				using (Pen p = new Pen (Brushes.Red)) {
					Assert.Throws<ArgumentException> (() => p.MultiplyTransform (noninvertible));
				}
			}
		}

		[Test]
		public void ResetTransform ()
		{
			using (Matrix m = new Matrix (2, 0, 0, 2, 10, -10)) {
				using (Pen p = new Pen (Brushes.Red)) {
					p.Transform = m;
					Assert.IsFalse (p.Transform.IsIdentity, "Transform.IsIdentity");
					p.ResetTransform ();
					Assert.IsTrue (p.Transform.IsIdentity, "Reset.IsIdentity");
				}
			}
		}

		[Test]
		public void RotateTransform ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				p.RotateTransform (90);
				float[] elements = p.Transform.Elements;
				Assert.AreEqual (0, elements[0], 0.1, "matrix.0");
				Assert.AreEqual (1, elements[1], 0.1, "matrix.1");
				Assert.AreEqual (-1, elements[2], 0.1, "matrix.2");
				Assert.AreEqual (0, elements[3], 0.1, "matrix.3");
				Assert.AreEqual (0, elements[4], 0.1, "matrix.4");
				Assert.AreEqual (0, elements[5], 0.1, "matrix.5");

				p.RotateTransform (270);
				Assert.IsTrue (p.Transform.IsIdentity, "Transform.IsIdentity");
			}
		}

		[Test]
		public void RotateTransform_InvalidOrder ()
		{
			Assert.Throws<ArgumentException> (() => default_pen.RotateTransform (720, (MatrixOrder) Int32.MinValue));
		}

		[Test]
		public void ScaleTransform ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				p.ScaleTransform (2, 4);
				float[] elements = p.Transform.Elements;
				Assert.AreEqual (2, elements[0], 0.1, "matrix.0");
				Assert.AreEqual (0, elements[1], 0.1, "matrix.1");
				Assert.AreEqual (0, elements[2], 0.1, "matrix.2");
				Assert.AreEqual (4, elements[3], 0.1, "matrix.3");
				Assert.AreEqual (0, elements[4], 0.1, "matrix.4");
				Assert.AreEqual (0, elements[5], 0.1, "matrix.5");

				p.ScaleTransform (0.5f, 0.25f);
				Assert.IsTrue (p.Transform.IsIdentity, "Transform.IsIdentity");
			}
		}

		[Test]
		public void ScaleTransform_MaxMin ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				p.ScaleTransform (Single.MaxValue, Single.MinValue);
				float[] elements = p.Transform.Elements;
				Assert.AreEqual (Single.MaxValue, elements[0], 1e33, "matrix.0");
				Assert.AreEqual (0, elements[1], 0.1, "matrix.1");
				Assert.AreEqual (0, elements[2], 0.1, "matrix.2");
				Assert.AreEqual (Single.MinValue, elements[3], 1e33, "matrix.3");
				Assert.AreEqual (0, elements[4], 0.1, "matrix.4");
				Assert.AreEqual (0, elements[5], 0.1, "matrix.5");
			}
		}

		[Test]
		public void ScaleTransform_InvalidOrder ()
		{
			Assert.Throws<ArgumentException> (() => default_pen.ScaleTransform (1, 1, (MatrixOrder) Int32.MinValue));
		}

		[Test]
		public void TranslateTransform ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				p.TranslateTransform (1, 1);
				float[] elements = p.Transform.Elements;
				Assert.AreEqual (1, elements[0], 0.1, "matrix.0");
				Assert.AreEqual (0, elements[1], 0.1, "matrix.1");
				Assert.AreEqual (0, elements[2], 0.1, "matrix.2");
				Assert.AreEqual (1, elements[3], 0.1, "matrix.3");
				Assert.AreEqual (1, elements[4], 0.1, "matrix.4");
				Assert.AreEqual (1, elements[5], 0.1, "matrix.5");

				p.TranslateTransform (-1, -1);
				elements = p.Transform.Elements;
				Assert.AreEqual (1, elements[0], 0.1, "revert.matrix.0");
				Assert.AreEqual (0, elements[1], 0.1, "revert.matrix.1");
				Assert.AreEqual (0, elements[2], 0.1, "revert.matrix.2");
				Assert.AreEqual (1, elements[3], 0.1, "revert.matrix.3");
				Assert.AreEqual (0, elements[4], 0.1, "revert.matrix.4");
				Assert.AreEqual (0, elements[5], 0.1, "revert.matrix.5");
			}
		}

		[Test]
		public void TranslateTransform_InvalidOrder ()
		{
			Assert.Throws<ArgumentException> (() => default_pen.TranslateTransform (1, 1, (MatrixOrder) Int32.MinValue));
		}

		[Test]
		public void Transform_Operations ()
		{
			using (Pen p = new Pen (Brushes.Red)) {
				Matrix clone = p.Transform.Clone ();
				Matrix mul = clone.Clone ();

				clone.Multiply (mul, MatrixOrder.Append);
				p.MultiplyTransform (mul, MatrixOrder.Append);
				Assert.AreEqual (p.Transform, clone, "Multiply/Append");

				clone.Multiply (mul, MatrixOrder.Prepend);
				p.MultiplyTransform (mul, MatrixOrder.Prepend);
				Assert.AreEqual (p.Transform, clone, "Multiply/Prepend");

				clone.Rotate (45, MatrixOrder.Append);
				p.RotateTransform (45, MatrixOrder.Append);
				Assert.AreEqual (p.Transform, clone, "Rotate/Append");

				clone.Rotate (45, MatrixOrder.Prepend);
				p.RotateTransform (45, MatrixOrder.Prepend);
				Assert.AreEqual (p.Transform, clone, "Rotate/Prepend");

				clone.Scale (0.25f, 2, MatrixOrder.Append);
				p.ScaleTransform (0.25f, 2, MatrixOrder.Append);
				Assert.AreEqual (p.Transform, clone, "Scale/Append");

				clone.Scale (0.25f, 2, MatrixOrder.Prepend);
				p.ScaleTransform (0.25f, 2, MatrixOrder.Prepend);
				Assert.AreEqual (p.Transform, clone, "Scale/Prepend");

				clone.Translate (10, 20, MatrixOrder.Append);
				p.TranslateTransform (10, 20, MatrixOrder.Append);
				Assert.AreEqual (p.Transform, clone, "Translate/Append");

				clone.Translate (30, 40, MatrixOrder.Prepend);
				p.TranslateTransform (30, 40, MatrixOrder.Prepend);
				Assert.AreEqual (p.Transform, clone, "Translate/Prepend");

				clone.Reset ();
				p.ResetTransform ();
				Assert.AreEqual (p.Transform, clone, "Reset");
			}
		}
	}
}
